﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Routing;
using Neto.Web.Listeners;

namespace Neto.Web;

/// <summary>
/// Web访问日志
/// </summary>
public class WebAccessLogFilter : IAsyncActionFilter
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    /// <param name="next"></param>
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var sw = new Stopwatch();
        sw.Start();

        // 获取控制器/操作描述器
        var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;

        // 获取请求方法
        var actionMethod = controllerActionDescriptor?.MethodInfo;

        // [DisplayName] 特性
        var displayNameAttribute = actionMethod != null && actionMethod.IsDefined(typeof(DisplayNameAttribute), true)
            ? actionMethod.GetCustomAttribute<DisplayNameAttribute>(true)
            : null;

        var webInfo = context.HttpContext.GetWebInfo();

        var sbInfo = new StringBuilder();
        sbInfo.AppendLine($"━━━━━━━━━━━━━━━  其它信息 ━━━━━━━━━━━━━━━");
        sbInfo.AppendLine($"##控制器名称## {controllerActionDescriptor?.ControllerTypeInfo.Name}");
        sbInfo.AppendLine($"##操作名称## {actionMethod?.Name}");
        sbInfo.AppendLine($"##显示名称## {displayNameAttribute?.DisplayName}");

        #region 拦截之前

        sbInfo.AppendLine($"读取参数前：{sw.Elapsed.TotalMilliseconds}");
        //提交的参数
        sbInfo.AppendLine($"参数 ActionArguments:{context.ActionArguments.ToJson()}");
        if (context.ModelState is { IsValid: false })
        {
            //验证信息
            var verifications =
                context.ModelState.ToDictionary(x => x.Key, v => v.Value.Errors.Select(o => o.ErrorMessage).ToList());
            sbInfo.AppendLine($"数据验证失败返回：{verifications.ToJson()}");
        }

        sbInfo.AppendLine($"\r\n操作用户ID：{App.HttpContext.GetLoginUserId()}");
        sbInfo.AppendLine($"\r\n操作用户账号：{App.HttpContext.GetLoginUserAccount()}");

        #endregion 拦截之前

        sbInfo.AppendLine($"执行next前：{sw.Elapsed.TotalMilliseconds}");
        //执行
        var resultContext = await next();

        sbInfo.AppendLine($"执行next后：{sw.Elapsed.TotalMilliseconds}");

        #region 拦截之后

        //访问返回
        switch (resultContext.Result)
        {
            //访问返回
            case JsonResult jsonResult:
            {
                sbInfo.AppendLine($"\r\n访问返回：{jsonResult?.Value?.ToJson()}");
                break;
            }
            case ContentResult contentResult:
            {
                sbInfo.AppendLine($"\r\n访问返回：{contentResult?.Content}");
                break;
            }
            case ObjectResult objectResult:
            {
                sbInfo.AppendLine($"\r\n访问返回：{objectResult?.Value?.ToJson()}");
                break;
            }
            case RedirectResult redirectResult:
            {
                sbInfo.AppendLine($"\r\n访问返回：{redirectResult?.Url}");
                break;
            }
            default:
            {
                sbInfo.AppendLine($"\r\n访问返回：{resultContext?.Result?.ToJson()}");
                break;
            }
        }

        #endregion 拦截之后

        var logFloderName = context.HttpContext.GetLogFloderName(context.RouteData);
        var _logger = LogX.GetLogger(logFloderName);
        // 异常拦截
        if (resultContext?.Exception != null)
        {
            //操作或操作筛选器导致异常
            // Exception thrown by action or action filter.
            // 设置为null以处理异常。
            //context.Exception = null;

            sbInfo.AppendLine($"\r\n异常：{resultContext.Exception.ToStringEx()}");
            _logger?.Error(sbInfo.ToString());
        }

        sw.Stop();
        sbInfo.AppendLine($"完成：{sw.Elapsed.TotalMilliseconds}");

        var netoConfigOption = AppX.GetConfig<NetoConfigOptions>();
        //写入文件
        if (netoConfigOption.Web.IsWebAccessLogWriteFile)
        {
            _logger?.Debug($"{webInfo.GetWebInfoToString()}\r\n{sbInfo.ToString()}");
        }

        //写入数据库
        if (netoConfigOption.Web.IsWebAccessLogWriteDb)
        {
            //执行注册的方法
            InvokeHelper.Execute(typeof(IWebAccessLogListener), "Log", 5,
                [context, resultContext, webInfo, sw.ElapsedMilliseconds, sbInfo.ToString()]);
        }
    }
}